package nc.vo.pubapp.pattern.model.entity.bill;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pub.ISuperVO;
import nc.vo.pub.IVOMeta;
import nc.vo.pub.SuperVO;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.pubapp.pattern.model.meta.entity.bill.AbstractBillMeta;
import nc.vo.pubapp.pattern.model.meta.entity.bill.IBillMeta;
import nc.vo.pubapp.pattern.pub.Constructor;
import nc.vo.trade.pub.IExAggVO;



public abstract class AbstractBill
  extends AggregatedValueObject
  implements Cloneable, IBill, IExAggVO
{
  private static final long serialVersionUID = -6588359712356277814L;
  private ISuperVO[][] children;
  private ISuperVO parent;
  
  public AbstractBill() {
    IBillMeta billMeta = getMetaData();
    int size = billMeta.getChildren().length;
    this.children = new ISuperVO[size][];
  }

  
  public Object clone() {
    AbstractBill bill = null;
    try {
      bill = (AbstractBill)super.clone();
    } catch (CloneNotSupportedException ex) {
      ExceptionUtils.wrappException(ex);
      return null;
    } 
    if (this.parent != null) {
      ISuperVO parentVO = (ISuperVO)this.parent.clone();
      bill.setParent(parentVO);
    } 
    bill.children = clone(this.children);
    return bill;
  }
  
  private ISuperVO[] clone(ISuperVO[] vos) {
    if (vos == null || vos.length == 0)
    {
      return vos;
    }
    int length = vos.length;
    Class<? extends ISuperVO> voClass = vos[0].getClass();
    ISuperVO[] newVOs = (ISuperVO[])Constructor.construct(voClass, length);
    for (int i = 0; i < length; i++) {
      newVOs[i] = (ISuperVO)vos[i].clone();
    }
    return newVOs;
  }
  
  private ISuperVO[][] clone(ISuperVO[][] vos) {
    int size = vos.length;
    ISuperVO[][] newChildren = new ISuperVO[size][];
    
    for (int i = 0; i < size; i++) {
      ISuperVO[] oldBodyVOs = vos[i];
      ISuperVO[] newBodyVOs = clone(oldBodyVOs);
      if (newBodyVOs != null)
      {
        
        newChildren[i] = newBodyVOs; } 
    } 
    return newChildren;
  }

  
  public ISuperVO[] getChildren(Class<? extends ISuperVO> clazz) {
    IBillMeta billMeta = getMetaData();
    IVOMeta voMeta = billMeta.getVOMeta(clazz);
    return getChildren(voMeta);
  }

  
  public ISuperVO[] getChildren(IVOMeta childMeta) {
    IBillMeta billMeta = getMetaData();
    IVOMeta[] childMetas = billMeta.getChildren();
    int index = getMetaIndex(childMetas, childMeta);
    return this.children[index];
  }


  
  public CircularlyAccessibleValueObject[] getChildrenVO() {
    IBillMeta billMeta = getMetaData();
    
    if (billMeta.getChildren().length == 0) {
      return null;
    }
    IVOMeta childMeta = billMeta.getChildren()[0];
    return (CircularlyAccessibleValueObject[])getChildren(childMeta);
  }
  
  private int getMetaIndex(IVOMeta[] metas, IVOMeta meta) {
    int length = metas.length;
    int cursor = -1;
    
    if (metas.length == 1) {
      return 0;
    }
    for (int i = 0; i < length; i++) {
      if (metas[i].equals(meta)) {
        cursor = i;
        
        break;
      } 
    } 
    if (cursor == -1) {
      ExceptionUtils.unSupported();
    }
    return cursor;
  }


  
  public ISuperVO getParent() { return this.parent; }



  
  public CircularlyAccessibleValueObject getParentVO() { return (CircularlyAccessibleValueObject)getParent(); }



  
  public String getPrimaryKey() { return this.parent.getPrimaryKey(); }

  
  private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    BillSerializer tool = new BillSerializer();
    tool.read(in, this);
  }

  
  public void setChildren(Class<? extends ISuperVO> clazz, ISuperVO[] vos) {
    IBillMeta billMeta = getMetaData();
    IVOMeta voMeta = billMeta.getVOMeta(clazz);
    setChildren(voMeta, vos);
  }

  
  public void setChildren(IVOMeta childMeta, ISuperVO[] items) {
    IBillMeta billMeta = getMetaData();
    IVOMeta[] childMetas = billMeta.getChildren();
    
    int index = getMetaIndex(childMetas, childMeta);
    this.children[index] = items;
  }


  
  public void setChildrenVO(CircularlyAccessibleValueObject[] vos) {
    ISuperVO[] items = (ISuperVO[])vos;
    IBillMeta billMeta = getMetaData();
    
    if (billMeta.getChildren().length == 0) {
      return;
    }
    IVOMeta childMeta = null;

    
    if (vos == null || vos.length == 0) {
      childMeta = billMeta.getChildren()[0];
    } else {
      childMeta = items[0].getMetaData();
    } 
    setChildren(childMeta, items);
  }


  
  public void setParent(ISuperVO parent) { this.parent = parent; }



  
  public void setParentVO(CircularlyAccessibleValueObject vo) { setParent((ISuperVO)vo); }

  
  private void writeObject(ObjectOutputStream out) throws IOException {
    BillSerializer tool = new BillSerializer();
    tool.write(out, this);
  }



  
  public CircularlyAccessibleValueObject[] getAllChildrenVO() { return getChildrenVO(); }



  
  public SuperVO[] getChildVOsByParentId(String tableCode, String parentid) { return null; }



  
  public String getDefaultTableCode() {
    String[] codes = getTableCodes();
    return (codes == null || codes.length == 0) ? null : codes[0];
  }


  
  public HashMap getHmEditingVOs() throws Exception { return null; }



  
  public String getParentId(SuperVO item) { return null; }




  
  public String[] getTableCodes() {
    if (!(getMetaData() instanceof AbstractBillMeta)) {
      return null;
    }
    AbstractBillMeta meta = (AbstractBillMeta)getMetaData();
    return meta.getAllSubAttrNames();
  }


  
  public String[] getTableNames() { return getTableCodes(); }




  
  public CircularlyAccessibleValueObject[] getTableVO(String tableCode) {
    if (!(getMetaData() instanceof AbstractBillMeta)) {
      return null;
    }
    AbstractBillMeta meta = (AbstractBillMeta)getMetaData();
    IVOMeta vometa = meta.getVOMeta(tableCode);
    ISuperVO[] vos = getChildren(vometa);




    
    if (vos != null) {
      return (CircularlyAccessibleValueObject[])vos;
    }
    return null;
  }




  
  public void setParentId(SuperVO item, String id) {}



  
  public void setTableVO(String tableCode, CircularlyAccessibleValueObject[] values) {
    if (!(getMetaData() instanceof AbstractBillMeta)) {
      return;
    }
    AbstractBillMeta meta = (AbstractBillMeta)getMetaData();
    IVOMeta vometa = meta.getVOMeta(tableCode);
    if (values instanceof ISuperVO[])
      setChildren(vometa, (ISuperVO[])values); 
  }
}